import odb
import helper
import odbUnitTest
import unittest


def placeInst(inst, x, y):
    inst.setLocation(x, y)
    inst.setPlacementStatus("PLACED")


def placeBPin(bpin, layer, x1, y1, x2, y2):
    odb.dbBox_create(bpin, layer, x1, y1, x2, y2)
    bpin.setPlacementStatus("PLACED")


class TestBlock(odbUnitTest.TestCase):
    def setUp(self):
        self.db, self.lib, self.design, self.ord_tech = helper.createSimpleDB()
        self.parentBlock = odb.dbBlock_create(self.db.getChip(), "Parent")
        self.block = helper.create2LevelBlock(self.db, self.lib, self.parentBlock)
        self.block.setCornerCount(4)
        self.extcornerblock = self.block.createExtCornerBlock(1)
        odb.dbTechNonDefaultRule_create(self.block, "non_default_1")
        self.parentRegion = odb.dbRegion_create(self.block, "parentRegion")

    def test_find(self):
        # bterm
        self.assertEqual(self.block.findBTerm("IN1").getName(), "IN1")
        self.assertIsNone(self.block.findBTerm("in1"))
        # child
        self.assertEqual(
            self.parentBlock.findChild("2LevelBlock").getName(), "2LevelBlock"
        )
        self.assertIsNone(self.parentBlock.findChild("1LevelBlock"))
        # inst
        self.assertEqual(self.block.findInst("i3").getName(), "i3")
        self.assertIsNone(self.parentBlock.findInst("i3"))
        # net
        self.assertEqual(self.block.findNet("n2").getName(), "n2")
        self.assertIsNone(self.block.findNet("a"))
        # iterm
        self.assertEqual(self.block.findITerm("i1,o").getInst().getName(), "i1")
        self.assertEqual(self.block.findITerm("i1,o").getMTerm().getName(), "o")
        self.assertIsNone(self.block.findITerm("i1\\o"))
        # extcornerblock
        self.assertEqual(
            self.block.findExtCornerBlock(1).getName(), "extCornerBlock__1"
        )
        self.assertIsNone(self.block.findExtCornerBlock(0))
        # nondefaultrule
        self.assertEqual(
            self.block.findNonDefaultRule("non_default_1").getName(), "non_default_1"
        )
        self.assertIsNone(self.block.findNonDefaultRule("non_default_2"))
        # region
        self.assertEqual(
            self.block.findRegion("parentRegion").getName(), "parentRegion"
        )

    def check_box_rect(self, min_x, min_y, max_x, max_y):
        box = self.block.getBBox()
        self.assertEqual(box.xMin(), min_x)
        self.assertEqual(box.xMax(), max_x)
        self.assertEqual(box.yMin(), min_y)
        self.assertEqual(box.yMax(), max_y)

    def block_placement(self, test_num, flag):
        if (flag and test_num == 1) or (not flag and test_num >= 1):
            if flag:
                print("here")
            placeInst(self.block.findInst("i1"), 0, 3000)
            placeInst(self.block.findInst("i2"), -1000, 0)
            placeInst(self.block.findInst("i3"), 2000, -1000)
        if (flag and test_num == 2) or (not flag and test_num >= 2):
            placeBPin(
                self.block.findBTerm("OUT").getBPins()[0],
                self.lib.getTech().findLayer("L1"),
                2500,
                -1000,
                2550,
                -950,
            )
        if (flag and test_num == 3) or (not flag and test_num >= 3):
            odb.dbObstruction_create(
                self.block, self.lib.getTech().findLayer("L1"), -1500, 0, -1580, 50
            )
        if (flag and test_num == 4) or (not flag and test_num >= 4):
            n_s = odb.dbNet_create(self.block, "n_s")
            swire = odb.dbSWire_create(n_s, "NONE")
            odb.dbSBox_create(
                swire, self.lib.getTech().findLayer("L1"), 0, 4000, 100, 4100, "NONE"
            )
        if (flag and test_num == 5) or (not flag and test_num >= 5):
            pass
            # TODO ADD WIRE

    def test_bbox0(self):
        box = self.block.getBBox()
        self.check_box_rect(0, 0, 0, 0)

    def test_bbox1(self):
        box = self.block.getBBox()
        self.block_placement(1, False)
        self.check_box_rect(-1000, -1000, 2500, 4000)

    def test_bbox2(self):
        box = self.block.getBBox()
        self.block_placement(2, False)
        self.check_box_rect(-1000, -1000, 2550, 4000)

    def test_bbox3(self):
        #         self.block_placement(2,False)
        #         box = self.block.getBBox()
        #         self.block_placement(3,True)
        placeInst(self.block.findInst("i1"), 0, 3000)
        placeInst(self.block.findInst("i2"), -1000, 0)
        placeInst(self.block.findInst("i3"), 2000, -1000)
        placeBPin(
            self.block.findBTerm("OUT").getBPins()[0],
            self.lib.getTech().findLayer("L1"),
            2500,
            -1000,
            2550,
            -950,
        )
        box = self.block.getBBox()
        odb.dbObstruction_create(
            self.block, self.lib.getTech().findLayer("L1"), -1500, 0, -1580, 50
        )
        self.check_box_rect(-1580, -1000, 2550, 4000)

    def test_bbox4(self):
        box = self.block.getBBox()
        self.block_placement(4, False)
        self.check_box_rect(-1580, -1000, 2550, 4100)


if __name__ == "__main__":
    unittest.main()
